masterofmagicfandomcom-20200216-history
User blog:Drake178/Colored Towers of Wizardry
So apparently, Towers of Wizardry were originally meant to show who their most recent occupier was after they have been cleared. Looking at the popped Tower graphic, an astute reader may notice that the green windows and top use colors that also appear on the raw database versions of City and Hero banners. This is not an accident. The Towers were actually meant to look like this: Unfortunately, the programmer that wrote the code for this was probably doing it at 5am in the morning; as they made two major mistakes. When a Tower is evaluated for display on the overland map, the game checks who its last controller was. If it is an intact Tower (controller = -1), it loads the intact tower image into its temporary work area; but if it isn't, it naturally loads the popped tower graphic instead. However, it doesn't actually display the latter as is. Instead, it goes through a short loop using the LBX_IMG_ColorReplace(unsigned IMG_Seg, char Orig_Color, char New_Color) function (WIZARDS.EXE $173E7), the very same way it does when drawing cities and Heroes. Except in this case, the coder mistakenly used the color index value that marks repeating pixels in RLE-encoded images (224, hex 0xE0), instead of that of the banner replacement colors (214, hex 0xD6). Since the former are not normally used in the images, nothing will be replaced by the function, and the Towers display as is. While this is a trivial thing to fix, a one byte change in the executable, that by itself won't yield the above result. Why? Because there's also another mistake in the code. The colors that are used as the "banner replacement colors" (these are also used for text display by the way, like highlighting the owners of enchantments) are stored in an array of 6 times 5 bytes, which I will call "B_Rep" here. To get the correct replacement color based on player index Pi, the following construct is normally used (i is the loop variable): Rep_Color = B_Rep[Wizardspi.BannerColor, i] Which has the alternative form of: Rep_Color = *(B_Rep + (WizardsPi.BannerColor * 5) + i) However, the Towers use this instead: Rep_Color = B_Rep + (WizardsPi.BannerColor * 5) Notice both the lack of the indirection operator (*), and the loop variable. Now, the latter may actually be intentional, but the former is most certainly not. It likely results from a source code of: Rep_Color = B_Rep[WizardsPi.BannerColor] This yields a near pointer to the array of 5 replacement colors. Amusingly enough, the B_Rep array is the very first global constant declared by the game, giving it an offset that can be passed as a color index even if it is the last element of the array that is being referenced. This makes the error quite tough to spot on a cursory look. It isn't until one fixes the first bug that it becomes apparent that the replacement colors are not the right ones. With regards to omitting the loop variable though, that may have been a design decision. The first colors of each set seem to be the brightest, and using them exclusively may improve visibility slightly, at the cost of losing a bit of the detail: Because of this, I've made a patch that requires only a single byte change to switch from one version to the other. To use it, save the contents of the box below into a text file in the MAGIC folder, and use the FILESET utility included with the Unofficial Patch 1.50 to apply it to WIZARDS.EXE. ; use a register instead of a local variable for the loop D2CA8 C7 56 D2CA9 46 90 D2CAA FA BE ; shorten the banner color retrieval D2CB0 46 5E D2CB2 BA 90 D2CB3 C8 69 D2CB4 04 DB D2CB5 F7 C8 D2CB6 EA 04 D2CB7 8B 8A D2CB8 D8 9F D2CB9 8A E0 D2CBA 87 9E D2CBB E0 30 D2CBC 9E FF D2CBD 98 6B D2CBE BA DB ; do the correct (pointer) arithmetic with the color constant D2CC0 00 8A D2CC1 F7 80 ;^^ change the above from 80 to 87 for the single color version D2CC2 EA AA D2CC3 05 00 D2CC4 AA B4 ; use the register loop value for the old color too D2CC7 8B 89 D2CC8 46 F0 D2CC9 FA 90 ; "banner replacement colors" instead of "repeat color" D2CCB E0 D6 ; loop tail D2CDA FF 90 D2CDC FA 90 D2CDE 7E FE D2CDF FA 05 D2CE0 05 7C D2CE1 7C CD ; restore the original register value D2CE2 CC 5E Category:Blog posts